package histogram_contour_plot;

require Exporter;
use lib ("/net/cpp-group/Leo/bin");


our @ISA = qw(Exporter);
our $VERSION = 1.00;
our @EXPORT = qw(   histogram_contour_plot);
use strict;
use warnings;
use Carp;
use SVG;
use Data::Dump qw(dump);
use nice_ticks;


#
#	Clip to extents
# 
sub create_cliprect($$)
{
	#<clipPath id="rectangle2">
	#<rect x="20" y="20" width="125" height="125" />
	#</clipPath>
	my ($svg, $range) = @_;
	my $clip_tag = $svg->clipPath(id=> 'clip', );
	$clip_tag->rectangle(	x   	=> $range->{x}{min}, 
							y		=> $range->{y}{min},
							width	=> $range->{x}{max} - $range->{x}{min}, 
							height	=> $range->{y}{max} - $range->{y}{min},
							id  	=> 'cliprect',
							style	=> {
								'fill'		=> "grey",
								'stroke'   	=>  "none"} 
						);
}





#
#	Draw one contour per percentile
# 
sub draw_contours($$)
{
	my ($svg, $data) = @_;

	# sort x data
	my @x_values = sort{$a <=>  $b} keys %$data;
	my @x_values_plot = (@x_values, reverse @x_values);
	my $contours=$svg->group(id    		=>  'contours');

	my $constant = 1.01;
	my $colour_max = ($constant**49);
	my $colour_min = ($constant**0);
	my $colour_range = ($colour_max - $colour_min);
	for (my $i = 0; $i < 50; $i++)
	{
		my @y_values;
		for my $x_val(@x_values)
		{
			push(@y_values, $data->{$x_val}[$i]);
		}
		for my $x_val(reverse @x_values)
		{
			push(@y_values, $data->{$x_val}[100 - $i]);
		}
		my $points = $svg->get_path(x		=> \@x_values_plot, y		=> \@y_values,
										-type		=> 'polygon',
										-closed		=> 'true');
		my $colour = $constant**$i;
		$colour = int(($colour - $colour_min) / $colour_range * 255);
#		my $colour = 255 - $i * 5;
		my $tag = $contours->polygon (
									%$points,
									id		=> 'pline_'.$i,
									style		=> {
										'fill-opacity'		=> 0.04,
										'fill'   			=>  "rgb($colour,$colour,$colour)" } );

	}
}


sub svg_drawline($\@\@$$)
{
	my ($svg, $x, $y, $colour, $name) = @_;
	my $points = $svg->get_path(x		=> $x, 
								y		=> $y,
								-type	=> 'polyline',
								-closed	=> 'false');
	return $svg->polyline (	%$points,
							id		=> $name,
							style			=> {
							fill			=> "none",
							'stroke-width'	=> 0.02,
							stroke   		=>  $colour } );
}


#
# 	set up ranges and tick marks
# 
sub setup_range($)
{
	my ($range) =@_;
	#
	# 	define ranges
	# 
	if (!defined $range->{y}{max})
	{
		croak "Error:\nOnly ymin defined and not ymax" if (defined $range->{ymin});
		$range->{y}{min} = 0;
		$range->{y}{min} = 10;
	}
	if (!defined $range->{x}{max})
	{
		croak "Error:\nOnly xmin defined and not xmax" if (defined $range->{xmin});
		$range->{x}{min} = 0;
		$range->{x}{min} = 10;
	}
	$range->{x}{min} ||= 0;
	$range->{y}{min} ||= 0;



	#
	# 	define tick marks
	# 
	if (!$range->{x}{major} || !$range->{x}{minor})
	{
		($range->{x}{min}, $range->{x}{max}, $range->{x}{major}, $range->{x}{format_str}, $range->{x}{minor}) = 
									nice_ticks($range->{x}{min}, $range->{x}{max}, 10, 2);
	}
	else
	{
		$range->{x}{format_str} = get_ticks_format_str($range->{x}{major});
	}


	if (!$range->{y}{major} || !$range->{y}{minor})
	{
		($range->{y}{min}, $range->{y}{max}, $range->{y}{major}, $range->{y}{format_str}, $range->{y}{minor}) = 
									nice_ticks($range->{y}{min}, $range->{y}{max}, 10, 2);
	}
	else
	{
		$range->{y}{format_str} = get_ticks_format_str($range->{y}{major});
	}
	
}


sub draw_axes($$$$$$)
{
	my ($major_axes, $minor_axes, $labels, $range1, $range2, $x_or_y) = @_;
	my ($axis1, $axis2) = ($x_or_y eq 'x') ? ('x', 'y') : ('y', 'x');

	my $text_size = ($range1->{max} - $range1->{min}) / 40;
	#
	# 	setup axis ranges to point to correct axis
	# 
	my ($axis1_min, $axis1_max) = ($range1->{'min'}, $range1->{'max'});
	my ($axis1_major, $axis1_minor) = ($range1->{'major'}, $range1->{'minor'});
	my ($axis2_min, $axis2_max) = ($range2->{'min'}, $range2->{'max'});

	# 
	#	Major grid marks
	# 
	#		don't draw frame (i.e. min or max)
	# 
	for (my $i = $axis1_min + $axis1_major; $i < $axis1_max - 0.5 * $axis1_major; $i += $axis1_major) 
	{
		$major_axes->line(
					$axis1.'1'		=> $i, 
					$axis2.'1'		=> $axis2_min,
					$axis1.'2'		=> $i, 
					$axis2.'2'		=> $axis2_max,
					style	=> {
					fill			=> "none",
					'stroke-width'	=> 0.02,
					stroke			=>  "rgb(0, 200, 0)"});
	}

	# 
	#	Minor grid marks, offset from major grid marks
	# 
	for (my $i = $axis1_min; $i < $axis1_max - 0.5 * $axis1_major; $i += $axis1_major) 
	{
		my $next_major = $i + $axis1_major;
		for (my $j = $i + $axis1_minor; $j < $next_major - 0.5 * $axis1_minor; 
															$j += $axis1_minor) 
		{
			$minor_axes->line(
						$axis1.'1'		=> $j, 
						$axis2.'1'		=> $axis2_min,
						$axis1.'2'		=> $j, 
						$axis2.'2'		=> $axis2_max,
						style	=> {
						fill			=> "none",
						'stroke-width'	=> 0.02,
						stroke			=>  "rgb(0, 0, 200)"} );
		}
	}
	# 
	#	Axes labels
	# 
	#		draw min or max as well
	# 
	my %text_styles = (
						$axis2		=> $axis2_min,
						'font-family'=> "Times New Roman",
						'font-size'	=> $text_size,
						fill		=> "blue");
	# set alignment
	if ($axis1 eq 'x')
	{
		$text_styles{'text-anchor'}	= 'middle';
	}
	else
	{
		$text_styles{$axis2} -= $text_size / 2;
		#$text_styles{'alignment-baseline'}	= 'middle';
	}

	for (my $i = $axis1_min; $i < $axis1_max + 0.5 * $axis1_major; $i += $axis1_major) 
	{
		my $label_text = sprintf($range1->{format_str}, $i);
		$text_styles{$axis1}		= $i;
		#$text_styles{-cdata}		= $label_text;
		$labels->text(%text_styles)->cdata($label_text);
	}



}
sub histogram_contour_plot(\%\%)
{
	my ($data, $range) =@_;

	#
	# 	set up ranges and tick marks
	# 
	setup_range($range);

	my $svg_base= SVG->new(	width		=> '8in',
							height		=> '11in', 
							style		=> "shape-rendering:geometricPrecision; text-rendering:geometricPrecision; image-rendering:optimizeQuality; fill-rule:evenodd; clip-rule:evenodd",
							viewBox		=> "$range->{x}{min} $range->{y}{min} ".
										($range->{x}{max} - $range->{x}{min}).' '.
										($range->{y}{max} - $range->{y}{min}),
							#transform => "scale ($scale)"
							); 
	
	my $svg = $svg_base->group(id =>  'whole_doc',
							   #transform => "scale (100)",
							   );



	# clip to extents
	create_cliprect($svg, $range);


	#
	#	Draw axes
	# 
	{
		#
		#	Draw Frame
		# 
		my $tag = $svg->rectangle(	x		=> $range->{x}{min}, 
									y		=> $range->{y}{min},
									width	=> $range->{x}{max} - $range->{x}{min}, 
									height	=> $range->{y}{max} - $range->{y}{min}, 
									id		=> 'frame',
									style	=> {
										fill			=> "none",
										'stroke-width'	=> 0.02,
										stroke			=> "rgb(0, 200, 0)"} );

		my $major_x_axes=$svg->group(id    		=>  'major_x_grid');
		my $minor_x_axes=$svg->group(id    		=>  'minor_x_grid');
		my $x_labels=$svg->group(id    			=>  'x_labels');
		draw_axes($major_x_axes, $minor_x_axes, $x_labels, $range->{x}, $range->{y}, 'x');

		my $major_y_axes=$svg->group(id    		=>  'major_y_grid');
		my $minor_y_axes=$svg->group(id    		=>  'minor_y_grid');
		my $y_labels=$svg->group(id    			=>  'y_labels');
		draw_axes($major_y_axes, $minor_y_axes, $y_labels, $range->{y}, $range->{x}, 'y');


	}


	#
	#	Draw one contour per percentile
	# 

	draw_contours($svg, $data);
	
	
	#
	#	Draw median and quartiles
	# 
	{
		my @x_values = sort{$a <=>  $b} keys %$data;
		my @y_values;
		@y_values = map {$data->{$_}[50]} @x_values;
		svg_drawline($svg, @x_values, @y_values, "rgb(255, 0, 0)", "median");
		@y_values = map {$data->{$_}[25]} @x_values;
		svg_drawline($svg, @x_values, @y_values, "rgb(255, 0, 0)", "25%");
		@y_values = map {$data->{$_}[75]} @x_values;
		svg_drawline($svg, @x_values, @y_values, "rgb(255, 0, 0)", "75%");
	}


	
		

	return $svg_base->xmlify;
}


1;
